(
    name: "StandardParticleSystemShader",

    resources: [
        (
            name: "diffuseTexture",
            kind: Texture(kind: Sampler2D, fallback: White),
            binding: 0
        ),
        (
            name: "fyrox_sceneDepth",
            kind: Texture(kind: Sampler2D, fallback: White),
            binding: 1
        ),
        (
            name: "properties",
            kind: PropertyGroup([
                (
                    name: "softBoundarySharpnessFactor",
                    kind: Float(value: 100.0),
                ),
                (
                    name: "useLighting",
                    kind: Bool(value: false),
                ),
            ]),
            binding: 0
        ),
        (
            name: "fyrox_instanceData",
            kind: PropertyGroup([
                // Autogenerated
            ]),
            binding: 1
        ),
        (
            name: "fyrox_cameraData",
            kind: PropertyGroup([
                // Autogenerated
            ]),
            binding: 2
        ),
        (
            name: "fyrox_lightsBlock",
            kind: PropertyGroup([
                // Autogenerated
            ]),
            binding: 3
        ),
        (
            name: "fyrox_lightData",
            kind: PropertyGroup([
                // Autogenerated
            ]),
            binding: 4
        ),
    ],

    disabled_passes: ["GBuffer", "DirectionalShadow", "PointShadow", "SpotShadow"],

    passes: [
        (
            name: "Forward",
            draw_parameters: DrawParameters(
                cull_face: None,
                color_write: ColorMask(
                    red: true,
                    green: true,
                    blue: true,
                    alpha: true,
                ),
                depth_write: false,
                stencil_test: None,
                depth_test: Some(Less),
                blend: Some(BlendParameters(
                    func: BlendFunc(
                        sfactor: SrcAlpha,
                        dfactor: OneMinusSrcAlpha,
                        alpha_sfactor: SrcAlpha,
                        alpha_dfactor: OneMinusSrcAlpha,
                    ),
                    equation: BlendEquation(
                        rgb: Add,
                        alpha: Add
                    )
                )),
                stencil_op: StencilOp(
                    fail: Keep,
                    zfail: Keep,
                    zpass: Keep,
                    write_mask: 0xFFFF_FFFF,
                ),
                scissor_box: None
            ),
            vertex_shader:
               r#"
               layout(location = 0) in vec3 vertexPosition;
               layout(location = 1) in vec2 vertexTexCoord;
               layout(location = 2) in float particleSize;
               layout(location = 3) in float particleRotation;
               layout(location = 4) in vec4 vertexColor;

               out vec2 texCoord;
               out vec4 color;
               out vec3 fragmentPosition;

               void main()
               {
                   color = S_SRGBToLinear(vertexColor);
                   texCoord = vertexTexCoord;
                   vec2 vertexOffset = S_RotateVec2(vertexTexCoord * 2.0 - 1.0, particleRotation);
                   vec4 worldPosition = fyrox_instanceData.worldMatrix * vec4(vertexPosition, 1.0);
                   vec3 offset = (vertexOffset.x * fyrox_cameraData.sideVector + vertexOffset.y * fyrox_cameraData.upVector) * particleSize;
                   vec4 finalPosition = worldPosition + vec4(offset.x, offset.y, offset.z, 0.0);
                   fragmentPosition = finalPosition.xyz;
                   gl_Position = fyrox_cameraData.viewProjectionMatrix * finalPosition;
               }
               "#,

           fragment_shader:
               r#"
               out vec4 FragColor;

               in vec2 texCoord;
               in vec4 color;
               in vec3 fragmentPosition;

               float toProjSpace(float z)
               {
                   return (fyrox_cameraData.zFar * fyrox_cameraData.zNear) / (fyrox_cameraData.zFar - z * fyrox_cameraData.zRange);
               }

               void main()
               {
                   ivec2 depthTextureSize = textureSize(fyrox_sceneDepth, 0);
                   vec2 pixelSize = vec2(1.0 / float(depthTextureSize.x), 1.0 / float(depthTextureSize.y));
                   float sceneDepth = toProjSpace(texture(fyrox_sceneDepth, gl_FragCoord.xy * pixelSize).r);
                   float fragmentDepth = toProjSpace(gl_FragCoord.z);
                   float depthOpacity = smoothstep((sceneDepth - fragmentDepth) * properties.softBoundarySharpnessFactor, 0.0, 1.0);

                   vec3 lighting;
                   if (properties.useLighting) {
                      lighting = fyrox_lightData.ambientLightColor.xyz;
                      for(int i = 0; i < min(fyrox_lightsBlock.lightCount, 16); ++i) {
                          // "Unpack" light parameters.
                          float halfHotspotAngleCos = fyrox_lightsBlock.lightsParameters[i].x;
                          float halfConeAngleCos = fyrox_lightsBlock.lightsParameters[i].y;
                          vec3 lightColor = fyrox_lightsBlock.lightsColorRadius[i].xyz;
                          float radius = fyrox_lightsBlock.lightsColorRadius[i].w;
                          vec3 lightPosition = fyrox_lightsBlock.lightsPosition[i];
                          vec3 direction = fyrox_lightsBlock.lightsDirection[i];

                          // Calculate lighting.
                          vec3 toFragment = fragmentPosition - lightPosition;
                          float distance = length(toFragment);
                          vec3 toFragmentNormalized = toFragment / distance;
                          float distanceAttenuation = S_LightDistanceAttenuation(distance, radius);
                          float spotAngleCos = dot(toFragmentNormalized, direction);
                          float directionalAttenuation = smoothstep(halfConeAngleCos, halfHotspotAngleCos, spotAngleCos);
                          lighting += lightColor * (distanceAttenuation * directionalAttenuation);
                      }
                   } else {
                      lighting = vec3(1.0);
                   }

                   FragColor = vec4(lighting, 1.0) * color * S_SRGBToLinear(texture(diffuseTexture, texCoord)).r;
                   FragColor.a *= depthOpacity;
               }
               "#,
        )
    ],
)